package com.lhj.xxsc.product.web;

import com.lhj.xxsc.product.entity.CategoryEntity;
import com.lhj.xxsc.product.service.CategoryService;
import com.lhj.xxsc.product.vo.Catelog2Vo;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author 罗惠江
 * @version 1.0
 * @email 1511619294@qq.com
 * @date 2020/12/2 11:57
 */
@Controller
public class IndexController {
	@Autowired
	RedissonClient redisson;

	@Autowired
	StringRedisTemplate redisTemplate;

	@Autowired
	CategoryService categoryService;

	@GetMapping({"/", "/index.html"})
	public String indexPage(Model model) {
		//TODO 1.查出一级分类数据
		List<CategoryEntity> categoryEntities = categoryService.getLevel1Categorys();

		model.addAttribute("categorys", categoryEntities);
		// 默认前缀:classpath:/templates/ 默认后缀:.html
		return "index";
	}

	@ResponseBody
	@GetMapping("/index/catalog.json")
	public Map<String, List<Catelog2Vo>> getCatelogJson() {
		Map<String, List<Catelog2Vo>> map = categoryService.getCatalogJson();
		return map;
	}


	//TODO 开始测试redisson
	@ResponseBody
	@GetMapping("/hello")
	public String hello() {

		// 1.获取到一把锁，只要锁的名字一样，那么他们就是同一把锁。
		RLock my_lock = redisson.getLock("my_lock");

		// 2.加锁
		//my_lock.lock();  // 阻塞式等待  默认都是30s过期时间，没有续期就会过期
		// 自定义的锁有redisson的看门狗，可以在锁过期之前自动续期。
		// 锁的业务只要运行完成，就不给当前锁续期，即使不手动解锁，默认也会在30s后自动解锁。
		my_lock.lock(10, TimeUnit.SECONDS);
		// 一般还是使用这种方式，避免业务导致整体死锁。
		// 我们定义了他10s 自动解锁。自定义的过期时间的模式，就不会触发看门狗模式
		// 如果我们未指定锁的时间，会使用默认的30*1000的时间，lockWatchdogTimeout 看门狗的默认时间

		//  只要占锁成功，就会启动一个定时任务【重新给锁设置过期时间，新的过期时间就是看门狗的默认时间】
		//  internalLockLeaseTime 定时任务是过期时间的1/3,然后在自己调用自己。
		try {
			System.out.println("加锁成功，执行业务。。。" + Thread.currentThread().getId());
			Thread.sleep(30000);
		} catch (Exception e) {

		} finally {
			// 3.解锁
			System.out.println("解锁成功。。。" + Thread.currentThread().getId());
			my_lock.unlock();
		}

		return "hello";
	}


	/**保证一定能读到最新的数据，修改期间，写锁是一个排他锁（互斥锁），读锁是一个共享锁
	 * 写锁没释放放读就必须等待
	 *
	 * 读写锁
	 * // 只要有写的操作都会阻塞，总结遇到写操作，就得等前面的操作执行完。
	 * 读写 就要等读操作结束。
	 * 写读 就要等写完
	 * 写写 也要等写结束
	 * 读读 就不会。
	 *
	 */
	@GetMapping("/write")
	@ResponseBody
	public String writeValue() {
		RReadWriteLock rw_lock = redisson.getReadWriteLock("rw-lock");
		String s = "";
		RLock rLock = rw_lock.writeLock();
		rLock.lock();
		try {
			// 1.改数据加写锁，读数据加读锁
			s = UUID.randomUUID().toString();
			Thread.sleep(30000);
			redisTemplate.opsForValue().set("DWValue", s);
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			rLock.unlock();
		}
		return s;
	}

	@GetMapping("/read")
	@ResponseBody
	public String readValue() {
		RReadWriteLock rw_lock = redisson.getReadWriteLock("rw-lock");
		String s = "";
		// 加读锁
		RLock rLock = rw_lock.readLock();
		rLock.lock();
		try {
			s = redisTemplate.opsForValue().get("DWValue");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			rLock.unlock();
		}
		return s;
	}
	/** 车库停车信号量模式
	 *  3 车位
	 * **/
	@GetMapping("/gogogo")
	@ResponseBody
	public String park() throws InterruptedException {
		RSemaphore park = redisson.getSemaphore("park");
		System.out.println(">?????????????????");
			// 获取一个信号，获取一个值
		park.acquire();
		System.out.println(">?????????????????");
			return "ok";


	}

	/** 车库停车信号量模式
	 *  3 车位
	 * **/
	@GetMapping("/go")
	@ResponseBody
	public String go(){
		RSemaphore park = redisson.getSemaphore("park");

			// 释放一个车位
			park.release();
			return "ok";


	}
	//TODO 结束测试redisson


}
